초기화 컨테이너
개요
init container.
직관적으로만 봐도 초기화를 진행하는 컨테이너라는 것을 알 수 있다.
이걸 통해 앱 컨테이너가 동작하기 전에 기본적으로 구축해야 할 설정과 동작을 수행할 수 있다.
참고로 여기에서 파생되어 나오는 것 중 하나가 사이드카 컨테이너이다.
특징
개념 자체는 쉬우니 바로 특징으로 넘어가도록 하자.
- 초기화 컨테이너는 반드시 종료되어야만 한다.
- 앱 컨테이너가 프로세스의 지속적인 작동을 전제하는 것과 다르다!
- 여러 개의 초기화 컨테이너를 둘 수 있다.
- 각 컨테이너는 순서대로 동작하며, 반드시 이전 컨테이너가 성공적으로 종료되었을 때 다음 컨테이너가 실행된다.
- 초기화 컨테이너가 성공적으로 종료되어야 비로소 앱 컨테이너가 동작한다.
- 초기화 컨테이너가 실패하면 kubelet은 파드 속 컨테이너의 장애#재시작 정책(restartPolicy)에 따라 관리한다.

위와 같이 초기화 컨테이너가 실행 중일 때 파드는 Pending상태에 머물러 있다.
다른 컨테이너와의 차이
- 리소스 제한 방식이 조금 다르다
- 앱 컨테이너와 리소스를 공유하지만, 동시에 돌아가는 일은 없다.
- 다만 볼륨에 선작업을 하는 듯이 작용하는 것은 가능하다.
- 라이프사이클, 컨테이너 프로브는 지원되지 않는다.
- 파드의 running 상태를 위해 종료되어야 하는 컨테이너이기 때문
- T-초기화 컨테이너에 프로브 넣기
- 사이드카 컨테이너는 다르니까 거기에서 참고하라.
사용법
초기화 컨테이너는 다음의 세 가지 상황에서 매우 유용하게 사용할 수 있다.
- 앱 컨테이너가 띄워지기 이전 확실하게 선행해야 하는 조건이 있을 때
- 다른 서비스가 켜져야만 제대로 돌아가는 파드라고 쳐보자.
- 이걸 컨테이너 프로브#startupProbe로 해결하는 방법도 있겠지만, 이는 지속적인 통신을 유발하고, 불필요하게 컨테이너가 오래 떠있게 만든다.
- 초기화 컨테이너에서 처리해버리면 불필요하게 앱 컨테이너가 오래 지속될 필요도 없다.
- 앱 이미지에서 하기 싫은 작업을 선행하고 싶을 때
- 앱 이미지 자체에 없는 디버깅 툴이나 설정 프로그램을 여기에서 선제적으로 깔고 작업을 진행할 수 있다.
- 필요하다면 볼륨으로 나중에 넘기면 된다.
- 앱 컨테이너에서 보안 취약점이 될 여지가 있는 유틸리티를 두지 않아도 된다.
- 앱 이미지에서 할 수 없는 작업을 할 때
- 초기화 컨테이너는 일반 앱 컨테이너와 다르게 Secret의 값을 뜯어볼 수 있다.
용례
for i in {1..100}; do sleep 1; if nslookup myservice; then exit 0; fi; done; exit 1
다른 서비스가 확실히 만들어지기 전까지 기다리기.
이 예시는 앱 컨테이너에 nslookup이 없어도 돼서 더 좋다.
curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
Downward API를 사용해 파드의 정보를 앱 실행 전에 등록하고 싶을 때.
sleep 60
그냥 시간 기다리기
이밖에도 깃 주소를 받아서 앱 컨테이너에 볼륨으로 공유하기, 템플릿 툴을 사용해 설정 파일을 앱 컨테이너에 공유하기 등의 작업을 수행할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app.kubernetes.io/name: MyApp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
위와 같이 until을 사용해서 내가 원하는 서비스가 올라올 때까지 대기를 시키는 방식은 매우 유용하다.
유의 사항
몇 가지 유의할 만한 사항이 있다.
초기화 컨테이너를 사용하는데 있어서 알아두면 둬야 할 상세 동작들이라고 할 수 있겠다.
재시작
restartPolicy에 대해
파드의 파드 속 컨테이너의 장애#재시작 정책(restartPolicy)을 따르지만, Always인 경우에는 OnFailure가 적용된다.
달리 말하자면 기본적으로 OnFailure이지만 파드의 재시작 정책이 Never인 경우에는 Never로 적용된다고 표현할 수도 있을 것 같다.
초기화 컨테이너가 성공적으로 수행되도 재시작된다면, 앱 컨테이너가 영원히 동작할 수 없으니 어쩌면 당연하다.
다른 문서에서 애매하게 적혀 있어서 T-초기화 컨테이너는 재시작되는가하는 고민까지 하게 만들어준 공식 문서에 다시금 감사를 표한다..
| 앱 컨테이너 정책 | 초기화 컨테이너 정책 |
|---|---|
| Always | OnFailure |
| OnFailure | OnFailure |
| Never | Never |
| 이렇게 정리해볼 수 있을 듯하다. |
파드의 재시작
초기화 컨테이너는 파드가 동작하는 시점에서 가장 선행되는 프로세스이다.
파드가 동작하는 시점이란 파드를 위한 네트워크, 스토리지 세팅이 완료된 이후를 말한다.
그래서 파드=초기화 컨테이너 정도의 밀접한 관계를 맺는다고도 말할 수 있다.
달리 말해 파드가 재시작하면 모든 초기화 컨테이너도 다시 실행한다.
이건 당연하게 들린다.
그러나 1.20 버전 이전에는 그 역도 거의 성립하다시피 했다.
현재는 그렇지는 않다고 하는 듯하다.
다음은 파드가 재시작되는 경우.
- 파드의 인프라 환경이 재설정됨.
- 실질적으로 누군가 루트 권한으로 노드를 조작한 것과 동일하기에 특수한 케이스
- 초기화 컨테이너 이미지를 변경함
- 재시작 정책이
Always인데 모든 초기화 컨테이너의 실행 정보가 가비지 컬렉팅됐고, 또한 모든 컨테이너가 종료되었음- 어차피 재시작을 걸긴 해야 하는데, 마침 초기화 컨테이너도 전부 실행 정보다 날아 버리면 그냥 파드가 재시작되는 ㄷㄷ
위 상황들이 궁금해서 조금 T-초기화 컨테이너의 이미지 바꾸기 테스트를 해봤다.
문서와는 조금 다른 구석이 있는 것 같으니 문서 설명을 너무 맹신하지는 말자.
결국 1.20 버전 이후부터는 첫번째 경우 말고는 파드가 재시작되는 경우가 없는 것으로 생각하면 될 듯하다.
리소스 공유
각 파드는 적정한 리소스 값을 가진다.
그리고 그것은 당연히 내부 컨테이너가 가질 수 있는 리소스 값에 달려있다.
이걸 왜 초기화 컨테이너에서 언급하는가?
초기화 컨테이너 중에서 가장 높게 리소스 제한이 걸린 값을 유효 초기 요청/제한이라고 부른다.
초기화 컨테이너 중 리소스 명시가 안 된 컨테이너는 이 값을 기준으로 제한이 걸린다.
이게 중요한 이유는 파드가 받을 수 있는 리소스의 값에 영향을 준다는 것이다.
파드의 리소스 스케줄링은 다음 중 더 높은 값을 토대로 이뤄진다.
- 모든 앱 컨테이너의 리소스 요청/제한 총량
- 유효한 초기 요청/제한
무슨 말이냐, 초기화 컨테이너는 파드의 라이프사이클에는 영향을 주지도 않는 주제에 파드의 리소스를 많이 걸어버릴 수도 있다는 것이다.
참고로 초기 컨테이너와 앱 컨테이너의 QoS 계층은 동일하다.
팁
케이스가 많지는 않지만, 초기화 컨테이너 역시 재시작될 가능성은 분명히 존재한다.
가령 모종의 이유로 컨테이너가 실패하게 된다던가 하는 상황이다.
그러니 멱등(idempotent)한 코드를 짜는 것이 중요하다.
EmptyDirs에 이전 초기화 컨테이너가 실행한 결과로 인한 오작동에 대한 대비책은 마련되어 있어야만 한다.
activeDeadlineSeconds를 써서 초기화 컨테이너가 무한 지속되는 상황을 미연에 방지할 수 있다.
그러나 이건 앱 컨테이너에도 적용되니까 한번 실행되고 끝나는 Job에 대해서만 적용하길 추천한다.
초기화 컨테이너끼리의 이름은 고유해야만 한다.